/* Licensed under the Apache License, Version 20.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.activiti.engine.test.db;

import java.sql.Connection;

import org.activiti.engine.impl.util.ReflectUtil;
import org.apache.ibatis.datasource.pooled.PooledDataSource;
import org.flowable.common.engine.impl.AbstractEngineConfiguration;
import org.flowable.engine.ProcessEngine;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.repository.DeploymentProperties;
import org.flowable.eventregistry.impl.cfg.StandaloneEventRegistryEngineConfiguration;
import org.flowable.eventregistry.impl.configurator.EventRegistryEngineConfigurator;

import junit.framework.TestCase;

/**
 * @author Daniel Meyer
 */
public class DatabaseTablePrefixTest extends TestCase {

    public void testPerformDatabaseSchemaOperationCreate() throws Exception {

        // both process engines will be using this datasource.
        PooledDataSource pooledDataSource = new PooledDataSource(ReflectUtil.getClassLoader(),
                "org.h2.Driver",
                "jdbc:h2:mem:activiti-test;DB_CLOSE_DELAY=1000",
                "sa",
                "");

        // create two schemas is the database
        Connection connection = pooledDataSource.getConnection();
        connection.createStatement().execute("drop schema if exists SCHEMA1");
        connection.createStatement().execute("drop schema if exists SCHEMA2");
        connection.createStatement().execute("create schema SCHEMA1");
        connection.createStatement().execute("create schema SCHEMA2");
        connection.close();

        // configure & build two different process engines, each having a separate table prefix
        ProcessEngineConfigurationImpl config1 = (ProcessEngineConfigurationImpl) ProcessEngineConfigurationImpl
                .createStandaloneInMemProcessEngineConfiguration()
                .setDataSource(pooledDataSource)
                .setDatabaseSchemaUpdate("NO_CHECK"); // disable auto create/drop schema
        config1.setDatabaseTablePrefix("SCHEMA1.");
        config1.setFlowable5CompatibilityEnabled(true);
        config1.setValidateFlowable5EntitiesEnabled(false);
        config1.getPerformanceSettings().setValidateExecutionRelationshipCountConfigOnBoot(false);
        config1.getPerformanceSettings().setValidateTaskRelationshipCountConfigOnBoot(false);
        config1.setEventRegistryConfigurator(new CustomEventRegistryEngineConfigurator());
        ProcessEngine engine1 = config1.buildProcessEngine();

        ProcessEngineConfigurationImpl config2 = (ProcessEngineConfigurationImpl) ProcessEngineConfigurationImpl
                .createStandaloneInMemProcessEngineConfiguration()
                .setDataSource(pooledDataSource)
                .setDatabaseSchemaUpdate("NO_CHECK"); // disable auto create/drop schema
        config2.setDatabaseTablePrefix("SCHEMA2.");
        config2.setFlowable5CompatibilityEnabled(true);
        config2.setValidateFlowable5EntitiesEnabled(false);
        config2.getPerformanceSettings().setValidateExecutionRelationshipCountConfigOnBoot(false);
        config2.getPerformanceSettings().setValidateTaskRelationshipCountConfigOnBoot(false);
        config2.setEventRegistryConfigurator(new CustomEventRegistryEngineConfigurator());
        ProcessEngine engine2 = config2.buildProcessEngine();

        // create the tables in SCHEMA1
        connection = pooledDataSource.getConnection();
        connection.createStatement().execute("set schema SCHEMA1");
        engine1.getManagementService().databaseSchemaUpgrade(connection, "", "SCHEMA1");
        connection.close();

        // create the tables in SCHEMA2
        connection = pooledDataSource.getConnection();
        connection.createStatement().execute("set schema SCHEMA2");
        engine2.getManagementService().databaseSchemaUpgrade(connection, "", "SCHEMA2");
        connection.close();

        // if I deploy a process to one engine, it is not visible to the other engine:
        try {
            engine1.getRepositoryService()
                    .createDeployment()
                    .addClasspathResource("org/activiti/engine/test/db/oneJobProcess.bpmn20.xml")
                    .deploymentProperty(DeploymentProperties.DEPLOY_AS_FLOWABLE5_PROCESS_DEFINITION, Boolean.TRUE)
                    .deploy();

            assertEquals(1, engine1.getRepositoryService().createDeploymentQuery().count());
            assertEquals(0, engine2.getRepositoryService().createDeploymentQuery().count());

        } finally {
            engine1.close();
            engine2.close();
        }
    }

    public class CustomEventRegistryEngineConfigurator extends EventRegistryEngineConfigurator {

        @Override
        public void configure(AbstractEngineConfiguration engineConfiguration) {
            if (eventEngineConfiguration == null) {
                eventEngineConfiguration = new StandaloneEventRegistryEngineConfiguration();
            }
            
            eventEngineConfiguration.setEnableEventRegistryChangeDetectionAfterEngineCreate(false);
            
            super.configure(engineConfiguration);
        }
    }
}
